using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Graphics;
using Microsoft.Xna.Framework.Content.Pipeline.Processors;
using Microsoft.Xna.Framework.Content;

namespace ContentPipelineExtension
{
    public class SpriteSheetXmlContent
    {
        public String FileName;
        public int FrameWidth;
        public int FrameHeight;
        public List<SpriteXmlContent> Sprites = new List<SpriteXmlContent>();
    }

    public class SpriteXmlContent
    {
        public int Id;
        public int MillisecondsPerFrame;
        public bool IsAnimated;
        public bool IsLooping;
        public List<TextureIndexXmlContent> TextureIndices = new List<TextureIndexXmlContent>();
    }

    public class TextureIndexXmlContent
    {
        public Point Index;
    }

    [ContentSerializerRuntimeType("JustinsGame.Engine.SpriteSheet, JustinsGame")]
    public class SpriteSheetContent
    {
        public Texture2DContent Texture = new Texture2DContent();
        public int FrameWidth;
        public int FrameHeight;
        public List<SpriteContent> Sprites = new List<SpriteContent>();
    }
    [ContentSerializerRuntimeType("JustinsGame.Engine.Sprite, JustinsGame")]
    public class SpriteContent
    {
        public int Id;
        public int MillisecondsPerFrame;
        public bool IsAnimated;
        public bool IsLooping;
        public List<Point> TextureIndices = new List<Point>();
        public int FrameWidth;
        public int FrameHeight;
    }

    /// <summary>
    /// This class will be instantiated by the XNA Framework Content Pipeline
    /// to apply custom processing to content data, converting an object of
    /// type TInput to TOutput. The input and output types may be the same if
    /// the processor wishes to alter data without changing its type.
    ///
    /// This should be part of a Content Pipeline Extension Library project.
    ///
    /// TODO: change the ContentProcessor attribute to specify the correct
    /// display name for this processor.
    /// </summary>
    [ContentProcessor(DisplayName = "ContentPipelineExtension.SpriteSheetProcessor")]
    public class SpriteSheetProcessor : ContentProcessor<SpriteSheetXmlContent, SpriteSheetContent>
    {
        public override SpriteSheetContent Process(SpriteSheetXmlContent input, ContentProcessorContext context)
        {
            SpriteSheetContent output = new SpriteSheetContent
            {
                FrameWidth = input.FrameWidth,
                FrameHeight = input.FrameHeight
            };

            // load texture sheet
            ExternalReference<TextureContent> textureReference = new ExternalReference<TextureContent>(input.FileName);
            TextureContent texture = context.BuildAndLoadAsset<TextureContent, TextureContent>(textureReference, "TextureProcessor");
            BitmapContent bitmap = texture.Faces[0][0];
            output.Texture.Mipmaps.Add(bitmap);

            // create the sprite objects
            List<SpriteContent> sprites = new List<SpriteContent>();
            foreach (SpriteXmlContent spriteXmlContent in input.Sprites)
            {
                SpriteContent spriteContent = new SpriteContent
                {
                    Id = spriteXmlContent.Id,
                    MillisecondsPerFrame = spriteXmlContent.MillisecondsPerFrame,
                    IsAnimated = spriteXmlContent.IsAnimated,
                    IsLooping = spriteXmlContent.IsLooping,
                    FrameWidth = input.FrameWidth,
                    FrameHeight = input.FrameHeight
                };

                List<Point> textureIndices = new List<Point>();
                foreach (TextureIndexXmlContent textureIndex in spriteXmlContent.TextureIndices)
                    textureIndices.Add(new Point(textureIndex.Index.X, textureIndex.Index.Y));

                spriteContent.TextureIndices = textureIndices;

                sprites.Add(spriteContent);
            }

            output.Sprites = sprites;

            return output;
        }
    }
}